Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

179
Views
Trying to wrap each word a user enters into a contenteditable="true" element in a div

The behavior I'm looking to implement would wrap each word the user types in <div class="word"></div> as they type their message. The parent div they're typing into has contenteditable="true".

One complicating factor is that for this use case one "word" div may contain two words (imagine a name would be considered one "word" so e.g. <div class="word">Bob Smith</div> may occur). This means I can't just grab all of the textContent when the user presses space and split(" ") into an array to build the div.word DOM elements.

I'm thinking when the user presses space I can get all the child nodes of the contenteditable div and loop through them to check which is a textNode and which is not (i.e. a word already wrapped in div.word). Then for the text nodes only I can build a div.word DOM element and append all of these to the contenteditable div.

I hope that's clear. Here's sort of where I'm at:

<div id="editor" contenteditable></div>
#editor {
  border: 1px solid #333;
  padding: 10px;
}

#editor .word {
  background: yellow;
  display: inline-block;
}
const editorElement = document.getElementById('editor');


function handleSpacebarPress() {
  // Get all editor child nodes
  let editorChildNodes = [...editor.childNodes];
  
  // Clear editor of all child nodes
  editor.innerHTML = '';
  
  editorChildNodes.forEach(node => {
    // If node is a text node (not a div.word element)
    if (node.nodeType === 3) {
      // Create div.word
      let wordDiv = document.createElement('div');
      wordDiv.className = 'word';
      wordDiv.textContent = node.textContent;
      
      editor.appendChild(wordDiv);
    } 
    // Else node is already a div.word element
    else {
        editor.appendChild(node);
    }
  });
  
  // Return caret to end of editor
  const editorLength = editor.childNodes.length;
  const lastNode = editor.childNodes[editorLength - 1]; // Last editor node
  
  const range = document.createRange();
  const selection = window.getSelection();
  
  range.setStart(lastNode, 1);
  range.collapse(true);
  selection.removeAllRanges();
  selection.addRange(range);
}


editorElement.addEventListener('keydown', e => {
  if (e.code === 'Space') {
    handleSpacebarPress();
  }
});

You can view this on jsfiddle here.

Right now it seems to just place all words directly into the one div.word element and I can't seem to handle creating a new one for each word.

Any ideas?

about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

I guess you want to achieve something like this: Highlighted Words Note how the spaces between the words are not highlighted and therefore have to be inside the main editor. You could fix this (as you pointed out in the comments) by adding spaces after each word in the editor and trim()-ming each word so that there are no spaces at the start or end of inner nodes.

You might to rethink your code, because it has some disadvantages.

  • Basically you are reimplementing what basic editors with custom syntax highlighting already do.
  • Manually setting the cursor position does not work, if you are editing in the middle of the editor.
  • Copy & pasting text wont trigger handleSpacebarPress

If you want to program the editor yourself, I suggest you use a function highlightWords that gets triggered after every change event (maybe with some artificial delay). In that function you can use a regular expression to find all the words according to your criteria and replace them with <span class=word>$1</span>.

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!